
package modele;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import modele.exceptions.InformationIndisponibleException;
import modele.exceptions.MatiereInexistanteException;

/**
 * Class RetourSurMatiere correspond à un retour qu'un étudiant fait sur une matière
 */
public class RetourSurMatiere extends Retour
{
    //La matière sur laquelle porte le retour
    private Matiere laMatiere;

    //L'étudiant qui a rédigé ce retour
    private Etudiant auteur;

    /**
     * Constructeur d'un RetourSurMatiere avec toutes les informations
     * @param id : l'identifiant du retour
     * @param texte : le texte du retour
     * @param etu : l'étudiant auteur du retour
     * @param mat : la matière sur laquelle porte le retour
     */
    public RetourSurMatiere(int id, String texte, Etudiant etu, Matiere mat)
    {
        super(id, texte);
        auteur = etu;
        laMatiere = mat;
    }

    /**
     * Constructeur partiel de RetourSurMatiere, ne doit être utilisé que lorsqu'on n'a
     * pas besoin des autres informations
     */
    public RetourSurMatiere(int id, String texte, Etudiant etu)
    {
        this(id, texte, etu, null);
    }

    /**
     * Constructeur partiel de RetourSurMatiere, ne doit être utilisé que lorsqu'on n'a
     * pas besoin des autres informations
     */
    public RetourSurMatiere(int id, String texte)
    {
        this(id, texte, null, null);
    }
    
    /**
     * Renvoie la matière sur laquelle porte le retour
     * @return la matière
     */
    public Matiere getMatiere() throws InformationIndisponibleException
    {
        if(laMatiere == null)
            throw new InformationIndisponibleException(Matiere.class, this.getClass());

        return laMatiere;
    }

    /**
     * Renvoie l'étudiant auteur du retour s'il est renseigné, une exception sinon
     * @return l'étudiant
     */
    public Etudiant getAuteur() throws InformationIndisponibleException
    {
        if(auteur == null)
            throw new InformationIndisponibleException(Etudiant.class, this.getClass());

        return auteur;
    }

    /**
     * Met à jour le retour à la fois en mémoire et en base de données
     * @param texte : le nouveau texte
     */
    @Override
    public void setTexte(String texte) throws SQLException
    {
        super.setTexte(texte);

        //Mise à jour dans la base de données

        String requete = "Update retour_sur_module set texte = ? where id_rsm = ?";
        Connection c = ConnexionBD.getConnection();
        PreparedStatement ps = c.prepareStatement(requete);
        ps.setString(1, texte);
        ps.setInt(2, getId());
        ps.executeUpdate();

        c.close();
    }

    //Méthodes statiques d'accès à la base de données

    /**
     * Renvoie le retour formulé sur une matière par un étudiant.
     * Si la matière n'existe pas, une exception sera levée.
     * Si le retour de l'étudiant sur la matière n'existe pas encore, on va le créer à vide.
     * On considère que l'étudiant demandé existe.
     * Visibilité package : Etudiant fera appel à cette méthode pour éviter le cas où l'étudiant n'existe pas.
     * @param id_matiere : l'identifiant de la matière
     * @param id_etudiant : l'identifiant de l'étudiant
     * @return le retour demandé avec seulement les identifiants de la matière et de l'étudiant
     * @throws MatiereInexistanteException si la matière n'existe pas
     */
    static RetourSurMatiere getRetour(int id_matiere, int id_etudiant) throws MatiereInexistanteException, SQLException
    {
        RetourSurMatiere resultat = null;

        //Vérifier que la matière existe
        Matiere m = Matiere.getMatiere(id_matiere);

        String requete = "Select id_rsm, texte from retour_sur_module where id_module = ? and id_etudiant = ?;";
        Connection c = ConnexionBD.getConnection();
        PreparedStatement ps = c.prepareStatement(requete);
        ps.setInt(1, id_matiere);
        ps.setInt(2, id_etudiant);
        ResultSet rs = ps.executeQuery();

        //L'étudiant a au maximum un retour sur une matière donnée
        if(rs.next())
        {
            //Récupération du retour s'il existe déjà
            int idrsm = (Integer) rs.getObject(1);
            String texte = (String) rs.getObject(2);
            resultat = new RetourSurMatiere(idrsm, texte, new Etudiant(id_etudiant), new Matiere(id_matiere));
        }
        else
        {
            //Création du retour s'il n'existe pas encore
            resultat = enregistrerNouveauRetour("", id_etudiant, id_matiere);
        }

        c.close();

        return resultat;

    }

    /**
     * Initialise et enregistre un nouveau retour dans la base de données
     * Il ne doit pas exister déjà en base de retour pour le couple auteur - laMatiere.
     * Visibilité private : Seulement les getRetour ont la faculté d'ajouter de nouveaux retours en base
     * @param texte : le texte du retour
     * @param auteur : l'étudiant auteur du retour
     * @param matiere : la matière sur laquelle porte le retour
     * @return le RetourSurMatiere créé et mis en base de données (avec seulement le texte)
     */
    private static RetourSurMatiere enregistrerNouveauRetour(String texte, int id_etudiant, int id_matiere) throws SQLException
    {
        String requete = "Insert into retour_sur_module(texte, id_etudiant, id_module) values(?, ?, ?);";
        Connection c = ConnexionBD.getConnection();
        PreparedStatement ps = c.prepareStatement(requete);
        ps.setString(1, texte);
        ps.setInt(2, id_etudiant);
        ps.setInt(3, id_matiere);

        ps.executeUpdate();

        //On récupère l'identifiant généré automatiquement de la base de données
        requete = "Select id_rsm from retour_sur_module where id_etudiant = ? and id_module = ?;";
        ps = c.prepareStatement(requete);
        ps.setInt(1, id_etudiant);
        ps.setInt(2, id_matiere);
        ResultSet rs = ps.executeQuery();

        rs.next();
        int idrsm = (Integer) rs.getObject(1);
        RetourSurMatiere r = new RetourSurMatiere(idrsm, texte);

        c.close();
        
        return r;
    }
  
}
